﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Common;
using DataAccess;
using Common.Views;

namespace BusinessLogic
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ProductsService" in code, svc and config file together.
    /// <summary>
    /// This service contains methods which send and get data regarding products to and from
    /// the Products, ProductCategories, ProductRatings, CommentsProducts and Carts tables in the database.
    /// </summary>
    public class ProductsService : IProductsService
    {
        /// <summary>
        /// A method which retreives all the products from the database
        /// </summary>
        /// <returns>A list of all the products found in the database</returns>
        public IEnumerable<Product> GetAllProducts()
        {
            return new ProductsRepository().GetAllProducts();
        }

        /// <summary>
        /// A method which retrieves a list of all the details for a particular product
        /// </summary>
        /// <param name="productID">The ID of the product for which to retreive the details</param>
        /// <param name="orderID">ID of the order for which to retrieve the details</param>
        /// <returns>A list of all the product details</returns>
        public OrdersView GetProductDetails(int productID, Guid orderID)
        {
            return new ProductsRepository().GetProductDetails(productID, orderID);
        }

        /// <summary>
        /// A method which retreives all the comments for a particular product
        /// </summary>
        /// <param name="id">The ID of the product for which to get the comments</param>
        /// <returns>A list of all the comments for a particular product</returns>
        public IEnumerable<CommentsProduct> GetCommentsForProduct(int id)
        {
            return new ProductsRepository().GetCommentsForProduct(id);
        }

        /// <summary>
        /// A method which adds a product to the user's cart
        /// </summary>
        /// <param name="username">The username of the user for whom the product is added to cart</param>
        /// <param name="productId">The ID of the product to be added to the cart</param>
        /// <param name="qty">The quantity of the product to be added to the cart</param>
        public string AddToCart(string username, int productId, int qty)
        {
            ProductsRepository pr = new ProductsRepository();
            Product p = pr.GetProduct(productId);
            if (p.Stock >= qty)
            {
                Cart sc = pr.GetCart(username, productId);
                if (sc == null)
                {
                    Cart c1 = new Cart()
                    {
                        Username = username,
                        ProductID = productId,
                        Quantity = qty
                    };
                    pr.AddToCart(c1);
                    return null;
                }
                else
                {
                    if (sc.ProductID == productId)
                    {
                        pr.UpdateCart(username, productId, qty);
                        return null;
                    }
                    else
                    {
                        Cart c2 = new Cart()
                        {
                            Username = username,
                            ProductID = productId,
                            Quantity = qty
                        };
                        pr.AddToCart(c2);
                        return null;
                    }
                }
            }
            else
                return "not enough stock";
        }

        /// <summary>
        /// A method which adds a new comment to a product in the database
        /// </summary>
        /// <param name="username">The username of the user who left the comment</param>
        /// <param name="productId">The ID of the product for which the comment is being left</param>
        /// <param name="comment">The comment regarding the product</param>
        public void AddComment(string username, int productId, string comment)
        {
            CommentsProduct cp = new CommentsProduct();
            cp.ProductID = productId;
            cp.Comment = comment;
            cp.Username = username;
            cp.Date = DateTime.Now;

            new ProductsRepository().AddComment(cp);
        }

        /// <summary>
        /// A method which retreives a list of products in a user's shopping cart
        /// </summary>
        /// <param name="username">The username for which the cart is being retreived</param>
        /// <returns>A list of products in a user's cart</returns>
        public IEnumerable<CartView> GetProductsInShoppingCart(string username)
        {
            return new ProductsRepository().GetProductsInShoppingCart(username);
        }

        /// <summary>
        /// A method which retreives the average rating for a particular product
        /// </summary>
        /// <param name="productId">The ID of the product for which to retreive the average rating</param>
        /// <returns>The average rating for a particular product</returns>
        public IEnumerable<int> GetRatingForProduct(int productId)
        {
            return new ProductsRepository().GetRatingForProduct(productId);
        }

        /// <summary>
        /// A method which adds a new rating for a particular product by a particular user
        /// </summary>
        /// <param name="username">The username who is rating the product</param>
        /// <param name="productId">The ID of the product being rated</param>
        /// <param name="rating">The rating of the product</param>
        /// <returns>A message if the user has already rated the product or null if not</returns>
        public string AddRatingForProduct(string username, int productId, int rating)
        {
            ProductsRepository r = new ProductsRepository();
            if (r.GetUserRatings(username, productId).Count() > 0)
                return "already rated";
            else
            {
                ProductRating pr = new ProductRating();
                pr.Username = username;
                pr.ProductID = productId;
                pr.Rating = rating;
                r.AddRatingForProduct(pr);

                return null;
            }
        }

        /// <summary>
        /// A method which retreives all the Product Categories
        /// </summary>
        /// <returns>A list of all the product categories</returns>
        public IEnumerable<ProductCategory> GetCategories()
        {
            return new ProductsRepository().GetProductCategories();
        }

        /// <summary>
        /// A method which gets a list of products according to their category
        /// </summary>
        /// <param name="categoryId">The ID of the category for which to get the products</param>
        /// <returns>A list of the products with the specified category</returns>
        public IEnumerable<Product> GetProductsByCategory(int categoryId)
        {
            return new ProductsRepository().GetProductsByCategory(categoryId);
        }

        /// <summary>
        /// A method which gets a list of products according to the keyword entered
        /// </summary>
        /// <param name="keyword">The word entered by the user which is used to get the products</param>
        /// <returns>A list of the products which contains the specified keyword in their name</returns>
        public IEnumerable<Product> GetProductsByName(string keyword)
        {
            return new ProductsRepository().GetProductByName(keyword);
        }

        /// <summary>
        /// A method which gets a list of products according to the price range
        /// </summary>
        /// <param name="min">The minimum price</param>
        /// <param name="max">The maximum price</param>
        /// <returns>A list of products which have a price between the min and max values</returns>
        public IEnumerable<Product> GetProductsByPrice(decimal min, decimal max)
        {
            return new ProductsRepository().GetProductByPrice(min, max);
        }

        /// <summary>
        /// A method which gets a list of products sorted by price in ascending order
        /// </summary>
        /// <returns>A list of products sorted by price (ascending)</returns>
        public IEnumerable<Product> SortByPriceAsc()
        {
            return new ProductsRepository().SortByPriceAsc();
        }

        /// <summary>
        /// A method which gets a list of products sorted by price in descending order
        /// </summary>
        /// <returns>A list of products sorted by price (descending)</returns>
        public IEnumerable<Product> SortByPriceDesc()
        {
            return new ProductsRepository().SortByPriceDesc();
        }

        /// <summary>
        /// A method which gets a list of products sorted by the date listed (latest first)
        /// </summary>
        /// <returns>A list of products sorted by the date listed (latest first)</returns>
        public IEnumerable<Product> SortByDateAsc()
        {
            return new ProductsRepository().SortByDateAsc();
        }
    }
}
